﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using WW.Cad.Drawing;
using WW.Cad.Drawing.GDI;
using WW.Cad.IO;
using WW.Cad.Model;
using WW.Cad.Model.Entities;
using WW.Cad.Model.Tables;
using WW.Drawing;
using WW.Math;

namespace ZhZyz.Cad
{
    public class CadServices
    {
        /// <summary>
        ///     检查图层，如果不存在就创建
        /// </summary>
        /// <param name="model">模型空间</param>
        /// <param name="layer">层名</param>
        /// <returns></returns>
        private static DxfLayer CheckLayer(DxfModel model, string layer)
        {
            var dxfLayer = model.GetLayerWithName(layer);
            if (dxfLayer != null) return dxfLayer;
            dxfLayer = new DxfLayer(layer);
            model.Layers.Add(dxfLayer);
            return dxfLayer;
        }

        /// <summary>
        ///     获取所有线图元
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static DxfEntity[] GetPlEntites(DxfModel model)
        {
            return model.Entities.FindAll(x => x.EntityType == "POLYLINE").ToArray();
        }

        /// <summary>
        ///     转换图元为geojson
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isWkt">是否输出WKT格式</param>
        /// <returns></returns>
        public static string ConvertEntToJson(DxfEntity entity,bool isWkt,bool plispg=false)
        {
            //生成geomerty格式geojson
            var stream = new MemoryStream();
             TextWriter xx = new StreamWriter(stream);
             JsonTextWriter writer = new JsonTextWriter(xx);
            writer.WriteStartObject();

            writer.WritePropertyName("type");
            writer.WriteValue("Feature");

            writer.WritePropertyName("properties");
            writer.WriteStartObject();
            //:todo 遍历基础属性
            WriteEntProperty(entity, writer);
            writer.WriteEndObject();

            writer.WritePropertyName("geometry");
         

            switch (entity.EntityType)
            {
                case "INSERT":
                    var insert = (DxfInsert) entity;
                    Write(insert, writer, isWkt);
                    break;
                case "POINT":
                    var pt = (DxfPoint) entity;
                    Write(pt, writer, isWkt);
                    break;
                case "LINE":
                    var ln = (DxfLine)entity;
                    Write(ln, writer, isWkt);
                    break;
                case "POLYLINE":
                    if (entity.AcClass == "AcDb2dPolyline")
                    {
                        var pl2d = (DxfPolyline2D)entity;
                        Write(pl2d, writer, isWkt, plispg);
                    }
                    else
                    {
                        var pl3d = (DxfPolyline3D)entity;
                        Write(pl3d, writer, isWkt, plispg);
                    }
                   
                    break;
                case "LWPOLYLINE":
                    var lwpl = (DxfLwPolyline) entity;
                    Write(lwpl, writer, isWkt, plispg);
                    break;
                case "TEXT":
                    var txt = (DxfText)entity;
                    Write(txt, writer, isWkt);
                    break;
            }
 

            writer.WriteEndObject();
            writer.Flush();
            return System.Text.Encoding.UTF8.GetString(stream.ToArray());
        }
        private static void WriteEntProperty(DxfEntity ent, JsonTextWriter writer)
        {
            writer.WritePropertyName("Layer");
            writer.WriteValue(ent.Layer.Name);
            writer.WritePropertyName("Color");
            writer.WriteValue(ent.Color.ColorIndex);
            writer.WritePropertyName("LineType");
            writer.WriteValue(ent.LineType.Name);
            writer.WritePropertyName("LineWeight");
            writer.WriteValue(ent.LineWeight);
            if (ent is DxfInsert)
            {
                writer.WritePropertyName("BlockName");
                writer.WriteValue((ent as DxfInsert).Block.Name);
                writer.WritePropertyName("Angle");
                writer.WriteValue((ent as DxfInsert).Rotation);
            }
            if (ent is DxfText)
            {
                writer.WritePropertyName("Text");
                writer.WriteValue((ent as DxfText).Text);
                writer.WritePropertyName("Height");
                writer.WriteValue((ent as DxfText).Height);
                     writer.WritePropertyName("Font");
                writer.WriteValue((ent as DxfText).Style.FontFamily.Name);

            }
        }
        public static void Write(DxfInsert ent, JsonTextWriter writer, bool isWkt)
        {
            if (isWkt)
            {
                writer.WriteValue($"POINT({ent.InsertionPoint.X} {ent.InsertionPoint.Y})");
            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                writer.WriteValue("Point");
                writer.WritePropertyName("coordinates");
                writer.WriteStartArray();
                writer.WriteValue(ent.InsertionPoint.X);
                writer.WriteValue(ent.InsertionPoint.Y);
                writer.WriteEndArray();
                writer.WriteEndObject();
            }
 
        }
        public static void Write(DxfPoint ent, JsonTextWriter writer, bool isWkt)
        {
            if (isWkt)
            {
                writer.WriteValue($"POINT({ent.Position.X} {ent.Position.Y})");
            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                writer.WriteValue("Point");
                writer.WritePropertyName("coordinates");
                writer.WriteStartArray();
                writer.WriteValue(ent.Position.X);
                writer.WriteValue(ent.Position.Y);
                writer.WriteEndArray();
                writer.WriteEndObject();
            }
        }
        public static void Write(DxfText ent, JsonTextWriter writer, bool isWkt)
        {
            if (isWkt)
            {
                writer.WriteValue($"POINT({ent.AlignmentPoint1.X} {ent.AlignmentPoint1.Y})");
            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                writer.WriteValue("Point");
                writer.WritePropertyName("coordinates");
                writer.WriteStartArray();
                writer.WriteValue(ent.AlignmentPoint1.X);
                writer.WriteValue(ent.AlignmentPoint1.Y);
                writer.WriteEndArray();
                writer.WriteEndObject();
            }

        }
        public static void Write(DxfLine ent, JsonTextWriter writer, bool isWkt)
        {
            if (isWkt)
            {
                List<string> coor = new List<string>();
                coor.Add($"{ent.Start.X} {ent.Start.Y}");
                coor.Add($"{ent.End.X} {ent.End.Y}");
                writer.WriteValue($"LINESTRING({string.Join(",", coor.ToArray())})");
            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                    writer.WriteValue("LineString");
                writer.WritePropertyName("coordinates");

                writer.WriteStartArray();

                    writer.WriteStartArray();
                    writer.WriteValue(ent.Start.X);
                    writer.WriteValue(ent.Start.Y);
                    writer.WriteEndArray();
                writer.WriteStartArray();
                writer.WriteValue(ent.End.X);
                writer.WriteValue(ent.End.Y);
                writer.WriteEndArray();

                writer.WriteEndArray();
  
                writer.WriteEndObject();
            }

        }
        public static void Write(DxfPolyline2D ent, JsonTextWriter writer, bool isWkt,bool plispg)
        {
            if (isWkt)
            {
                List<string> coor = new List<string>();
                foreach (var pver in ent.Vertices)
                {
                    coor.Add($"{pver.X} {pver.Y}");
                }
                if (plispg)
                {
                    writer.WriteValue($"POLYGON(({string.Join(",", coor.ToArray())}))");
                }
                else
                {
                    if (ent.Closed && ent.Vertices[ent.Vertices.Count - 1] != ent.Vertices[0])
                        coor.Add($"{ent.Vertices[0].X} {ent.Vertices[0].Y}");
                    writer.WriteValue($"LINESTRING({string.Join(",", coor.ToArray())})");
                }

            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                if (plispg) { writer.WriteValue("Polygon"); }
                else
                {
                    writer.WriteValue("LineString");
                }

                writer.WritePropertyName("coordinates");
                if (plispg) writer.WriteStartArray();

                writer.WriteStartArray();
                foreach (var pver in ent.Vertices)
                {
                    writer.WriteStartArray();
                    writer.WriteValue(pver.X);
                    writer.WriteValue(pver.Y);
                    writer.WriteEndArray();
                }
                writer.WriteEndArray();
                if (plispg) writer.WriteEndArray();
                writer.WriteEndObject();
            }

        }
        public static void Write(DxfPolyline3D ent, JsonTextWriter writer, bool isWkt, bool plispg)
        {
            if (isWkt)
            {
                List<string> coor = new List<string>();
                foreach (var pver in ent.Vertices)
                {
                    coor.Add($"{pver.X} {pver.Y}");
                }
                if (plispg)
                {
                    writer.WriteValue($"POLYGON(({string.Join(",", coor.ToArray())}))");
                }
                else
                {
                    if (ent.Closed && ent.Vertices[ent.Vertices.Count - 1] != ent.Vertices[0])
                        coor.Add($"{ent.Vertices[0].X} {ent.Vertices[0].Y}");
                    writer.WriteValue($"LINESTRING({string.Join(",", coor.ToArray())})");
                }

            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                if (plispg) { writer.WriteValue("Polygon"); }
                else
                {
                    writer.WriteValue("LineString");
                }

                writer.WritePropertyName("coordinates");
                if (plispg) writer.WriteStartArray();

                writer.WriteStartArray();
                foreach (var pver in ent.Vertices)
                {
                    writer.WriteStartArray();
                    writer.WriteValue(pver.X);
                    writer.WriteValue(pver.Y);
                    writer.WriteEndArray();
                }
                writer.WriteEndArray();
                if (plispg) writer.WriteEndArray();
                writer.WriteEndObject();
            }

        }
        public static void Write(DxfLwPolyline ent, JsonTextWriter writer, bool isWkt,bool plispg)
        {
            if (isWkt)
            {
                List<string> coor = new List<string>();
                foreach (var pver in ent.Vertices)
                {
                    coor.Add($"{pver.X} {pver.Y}");
                }
                if (plispg)
                {
                    writer.WriteValue($"POLYGON(({string.Join(",", coor.ToArray())}))");
                }
                else
                {
                    if (ent.Closed && ent.Vertices[ent.Vertices.Count - 1] != ent.Vertices[0])
                        coor.Add($"{ent.Vertices[0].X} {ent.Vertices[0].Y}");
                    writer.WriteValue($"LINESTRING({string.Join(",", coor.ToArray())})");
                }
             
            }
            else
            {
                writer.WriteStartObject();
                writer.WritePropertyName("type");
                if (plispg) { writer.WriteValue("Polygon"); }else
                {
                    writer.WriteValue("LineString");
                }
                
                writer.WritePropertyName("coordinates");
                if (plispg) writer.WriteStartArray();

                writer.WriteStartArray();
                                foreach (var pver in ent.Vertices)
                {
                    writer.WriteStartArray();
                    writer.WriteValue(pver.X);
                    writer.WriteValue(pver.Y);
                    writer.WriteEndArray();
                }
                writer.WriteEndArray();
                if (plispg) writer.WriteEndArray();
                writer.WriteEndObject();
            }
        }
        /// <summary>
        ///     获取文件预览图形
        /// </summary>
        /// <param name="filecontent">文件流字节数组</param>
        /// <param name="isdxf">是否为DXF文件内容</param>
        /// <returns></returns>
        public static Image GetImage(byte[] filecontent, bool isdxf = true)
        {
            if (filecontent == null) return null;
            var memory = new MemoryStream(filecontent);
            var model = isdxf ? DxfReader.Read(memory) : DwgReader.Read(memory);
            var imgbytes = ConvertPic(model);
            memory = new MemoryStream(imgbytes);
            return Image.FromStream(memory);
        }

        public static Image GetImage(string filename)
        {
            return GetImage(File.ReadAllBytes(filename),
                filename.EndsWith(".dxf", StringComparison.CurrentCultureIgnoreCase));
        }

        public static Image GetImage(DxfModel model)
        {
            var imgbytes = ConvertPic(model);
            var memory = new MemoryStream(imgbytes);
            return Image.FromStream(memory);
        }

        /// <summary>
        ///     DXFModel转成png图片
        /// </summary>
        /// <param name="model"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns>byte[]字节数组</returns>
        private static byte[] ConvertPic(DxfModel model, int width = 900, int height = 700)
        {
            var maxSize = new Size(width, height);
            var graphics = new GDIGraphics3D(); //GraphicsConfig.AcadLikeWithWhiteBackground);
            var gc = new GraphicsConfig
            {
                DrawHatchPatterns = true,
                BackColor = ArgbColor.FromArgb(ArgbColors.White.Argb, true) //背景色白色
            };
            graphics.GraphicsConfig = gc;
            graphics.CreateDrawables(model);
            using (var bitmap = ImageExporter.CreateAutoSizedBitmap(model, graphics, Matrix4D.Identity, maxSize))
            {
                using (Stream stream = new MemoryStream())
                {
                    ImageExporter.EncodeImageToPng(bitmap, stream); //转成png
                    //ImageExporter.EncodeImageToJpeg(bitmap, stream);
                    var slen = stream.Length;
                    var rbs = new byte[slen];
                    stream.Position = 0;
                    stream.Read(rbs, 0, (int)slen);
                    return rbs;
                }
            }
        }
    }
}